package xm.core
{
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	
	import xm.events.XMStateEvent;
	import xm.interfaces.ILifeCycle;
	import xm.namespaces.xprimeMobile;
	
	
	//-----------------------------------------------------------------------------------
	// namespace
	//-----------------------------------------------------------------------------------
	use namespace xprimeMobile;
	
	
	/**
	 * 생성시점 
	 */	
	[Event(name="stateInitialize", type="xm.events.XMStateEvent")]
	
	/**
	 * 속성 설정 
	 */	
	[Event(name="stateCommitProperties", type="xm.events.XMStateEvent")]
	
	/**
	 * 속성 설정 완료
	 */	
	[Event(name="stateCommitPropertiesComplete", type="xm.events.XMStateEvent")]
	
	/**
	 * 자식 생성
	 */	
	[Event(name="stateCreateChildren", type="xm.events.XMStateEvent")]
	
	/**
	 * 속성, 자식 등 전체 생성 완료 
	 */	
	[Event(name="stateCreationComplete", type="xm.events.XMStateEvent")]
	
	/**
	 * 화면 렌더링 시작. 
	 */	
	[Event(name="stateUpdateDisplayList", type="xm.events.XMStateEvent")]
	
	/**
	 * 화면 렌더링 끝남. 
	 */	
	[Event(name="stateUpdateDisplayListComplete", type="xm.events.XMStateEvent")]
	
	/**
	 * 화면에 add 됨 
	 */	
	[Event(name="stateAdd", type="xm.events.XMStateEvent")]
	
	/**
	 * 화면에서 remove 됨 
	 */	
	[Event(name="stateRemove", type="xm.events.XMStateEvent")]
	
	/**
	 * 제거됨. 
	 */	
	[Event(name="stateDestroy", type="xm.events.XMStateEvent")]
	
	/**
	 * <br> 클래스 설명 : XprimeMobile Framework 의 기본 Sprite</br>
	 * @author 김정환
	 */	
	public class XMSprite extends Sprite implements ILifeCycle
	{
		
		/**
		 *  @private
		 *  결과적으로 commitProperties() 을 호출하게 된다. 
		 */
		xprimeMobile var invalidatePropertiesFlag:Boolean = false;
		
		
		/**
		 *  @private
		 *  결과적으로 createChildren() 을 호출하게 된다.
		 */
		xprimeMobile var invalidateChildrenFlag:Boolean = false;
		
		/**
		 *  @private
		 *  결과적으로 updateDisplayList() 을 호출하게 된다.
		 */
		xprimeMobile var invalidateDisplayListFlag:Boolean = false;
		
		
		//-----------------------------------------------------------------------------------
		// public vars
		//-----------------------------------------------------------------------------------
		
		/** 배경색상 default : 0xffffff;  **/
		public var backgroundColor : uint = 0xffffff;
		
		/** 배경 알파 **/
		public var backgroundAlpha : Number = 1;
		
		
		/** 보더 - 상단 색상 **/
		public var borderTopColor : uint = 0xffffff;
		/** 보더 - 우측 색상 **/
		public var borderRightColor : uint = 0xffffff;
		/** 보더 - 하단 색상 **/
		public var borderBottomColor : uint = 0xffffff;
		/** 보더 - 좌측 색상 **/
		public var borderLeftColor : uint = 0xffffff;
		
		
		/** 보더 - 상단 알파 **/
		public var borderTopAlpha : Number = 1;
		/** 보더 - 우측 알파 **/
		public var borderRightAlpha : Number = 1;
		/** 보더 - 하단 알파 **/
		public var borderBottomAlpha : Number = 1;
		/** 보더 - 좌측 알파 **/
		public var borderLeftAlpha : Number = 1;
		
		
		/** 보더 - 상단 두께 **/
		public var borderTopThickness : Number = 0;
		/** 보더 - 우측 두께 **/
		public var borderRightThickness : Number = 0;
		/** 보더 - 하단 두께 **/
		public var borderBottomThickness : Number = 0;
		/** 보더 - 좌측 두께 **/
		public var borderLeftThickness : Number = 0;
		
		
		
		
		/**
		 *  paddingTop
		 */		
		public var paddingTop : Number = 0;
		
		/**
		 *  paddingRight
		 */		
		public var paddingRight : Number = 0;
		
		/**
		 *  paddingBottom
		 */		
		public var paddingBottom : Number = 0;
		
		/**
		 * paddingLeft 
		 */		
		public var paddingLeft : Number = 0;
		
		
		//-----------------------------------------------------------------------------------
		// protected / internal vars
		//-----------------------------------------------------------------------------------
		
		/**
		 * 백그라운드 색상 및 보더를 위한 쉐이프.
		 */		
		protected var bg : Shape;
		
		/**
		 * 생성및 파기를 위한 단계별 넘버변수 ( 내부용 )
		 */		
		protected var statusNum : Number = 0;
		
		
		//-----------------------------------------------------------------------------------
		// private vars
		//-----------------------------------------------------------------------------------
		
		private var _isCreated : Boolean = false;
		
		private var _viewWidth : Number = 0;
		
		private var _viewHeight : Number = 0;
		
		
		//-----------------------------------------------------------------------------------
		// public functions
		//-----------------------------------------------------------------------------------
		/**
		 * constructor 
		 */		
		public function XMSprite()
		{
			super();
			
			var xmStateEvent : XMStateEvent = new XMStateEvent( XMStateEvent.STATE_INITIALIZE, false, false );
			dispatchEvent( xmStateEvent );
			
			invalidateProperties();
			invalidateChildren();
			
		}
		
		
		
		/**
		 * invalidateProperties
		 */		
		public function invalidateProperties():void
		{
			if( invalidatePropertiesFlag == false )
			{
				invalidatePropertiesFlag = true;
				XprimeMobileGlobals.layoutManager.invalidatePropertiesQueue( this );
			}
		}
		
		/**
		 * invalidateChildren
		 */		
		public function invalidateChildren():void
		{
			if( invalidateChildrenFlag == false )
			{
				invalidateChildrenFlag = true;
				XprimeMobileGlobals.layoutManager.invalidateChildrenQueue( this );
			}
		}
		
		/**
		 * invalidateDisplayList
		 */		
		public function invalidateDisplayList():void
		{
			if( invalidateDisplayListFlag == false )
			{
				invalidateDisplayListFlag = true;
				XprimeMobileGlobals.layoutManager.invalidateDisplayListQueue( this );
			}
		}
		
		
		/**
		 * commitProperties
		 */		
		public function commitProperties():void
		{
			if( invalidatePropertiesFlag == false ) return;
			
			dispatchEvent( new XMStateEvent( XMStateEvent.STATE_COMMIT_PROPERTIES, false, false ) );
			
			addEventListener(Event.ADDED_TO_STAGE, onAddedToStage );
			addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage );
			
		}
		
		
		/**
		 * updateDisplayList
		 */		
		public function updateDisplayList( enforce : Boolean = false ):void
		{
			if( statusNum == -1 ) return;
			
			if( _isCreated == false )
			{
				invalidateChildren();
				return;
			}
			if( enforce == false && invalidateDisplayListFlag == false ) return;
			
			dispatchEvent( new XMStateEvent( XMStateEvent.STATE_UPDATE_DISPLAY_LIST, false, false ) );
			
			drawBg();
		}
		
		
		
		//-----------------------------------------------------------------------------------
		// life cycle functions
		//-----------------------------------------------------------------------------------
		
		
		/**
		 * createChildren
		 */		
		public function createChildren():void
		{
			if( invalidatePropertiesFlag == true ) invalidateProperties();
			if( invalidateChildrenFlag == false ) return;
			
			var xmStateEvent : XMStateEvent = new XMStateEvent( XMStateEvent.STATE_CREATE_CHILDREN, false, false );
			dispatchEvent( xmStateEvent );
			
			bg = new Shape();
			addChild( bg );
		}
		
		
		/**
		 * createComplete
		 */		
		public function creationComplete():void
		{
			if( invalidatePropertiesFlag == true ) invalidateProperties();
			if( invalidateChildrenFlag == true ) invalidateChildren();
			if( _isCreated == true ) return; 
			
			_isCreated = true;
			invalidateDisplayList();
			if( this.parent != null ) add();
		}
		
		
		/**
		 * add ( 화면에 붙자마자 발생 )
		 */		
		public function add():void
		{
			if( _isCreated == false ) return;
			
			var xmStateEvent : XMStateEvent = new XMStateEvent( XMStateEvent.STATE_ADD, false, false );
			dispatchEvent( xmStateEvent );
		}

		
		/**
		 * remove ( 화면에서 떨어지자마자 발생 )</ br>
		 * 초기화 메서드로 적당함.
		 */
		public function remove():void
		{
			var xmStateEvent : XMStateEvent = new XMStateEvent( XMStateEvent.STATE_REMOVE, false, false );
			dispatchEvent( xmStateEvent );
		}
		
		/**
		 * destroy
		 */		
		public function destroy():void
		{
			var xmStateEvent : XMStateEvent, len : int;
			
			statusNum = -1;
			
			xmStateEvent = new XMStateEvent( XMStateEvent.STATE_DESTROY, false, false );
			dispatchEvent( xmStateEvent );
			
			
			
			// 이벤트 리스너 제거.
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage );
			removeEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage );
			
			
			
			// 만약 아직 remove() 단계가 아니면 강제 Remove 시킴.
			if( parent != null && parent.contains( this ) ) parent.removeChild( this );
			
			
			// 속성 제거.
			backgroundAlpha = NaN;
			backgroundColor = 0;
			
			padding = [NaN,NaN,NaN,NaN];
			borderAlpha = [NaN,NaN,NaN,NaN];
			borderThickness = [NaN,NaN,NaN,NaN];
			borderColor = [0,0,0,0];
			
			if( bg )
			{
				if( bg.parent ) bg.parent.removeChild( bg );
				bg = null;
			}
			
			_isCreated = false;
			invalidatePropertiesFlag = false;
			invalidateChildrenFlag = false;
			invalidateDisplayListFlag = false;
			
			
		
			
			// 자식들 제거.
			len = numChildren;
			
			while( --len>0 )
			{
				if( getChildAt( len ) is XMSprite )
				{
					( getChildAt( len ) as XMSprite ).destroy();
				}
			}
			
			
		}
		
		
		
		
		//-----------------------------------------------------------------------------------
		// setter / getter
		//-----------------------------------------------------------------------------------
		
		
		/**
		 * <br>화면에 표시하고자 하는 너비</br>
		 * <=> width ( 플래시 기본엔진에 의해 measured된 너비 )
		 */
		public function get viewWidth():Number
		{
			return _viewWidth;
		}
		
		/**
		 * @private
		 */
		public function set viewWidth(value:Number):void
		{
			_viewWidth = value;
		}
		
		/**
		 * <br>화면에 표시하고자 하는 높이</br>
		 * <=> height ( 플래시 기본엔진에 의해 measured된 높이 ) 
		 */
		public function get viewHeight():Number
		{
			return _viewHeight;
		}
		
		/**
		 * @private
		 */
		public function set viewHeight(value:Number):void
		{
			_viewHeight = value;
		}

		
		/**
		 * @return 생성완료 여부
		 */		
		public function get isCreated():Boolean
		{
			return _isCreated;
		}

		
		/**
		 * <br>패딩값 default : 0,0,0,0</br>
		 * <br> - 시계방향으로 위, 오른쪽, 아래, 왼쪽 순서임 </br> 
		 */
		public function get padding():Array
		{
			return [paddingTop, paddingRight, paddingBottom, paddingLeft];
		}
		
		/**
		 * @private : Array - 상, 우, 하, 좌 ( 시게방향 )
		 */
		public function set padding(value:Array):void
		{
			paddingTop = value[ 0 ];
			paddingRight = value[ 1 ];
			paddingBottom = value[ 2 ];
			paddingLeft = value[ 3 ];
		}
		
		/**
		 * @param value : Array - 상, 우, 하, 좌
		 * @return 
		 */		
		public function set borderColor( value:Array ):void
		{
			borderTopColor = value[ 0 ];
			borderRightColor = value[ 1 ];
			borderBottomColor = value[ 2 ];
			borderLeftColor = value[ 3 ];
		}
		
		/**
		 * @param value
		 * @return 
		 */		
		public function set borderAlpha( value:Array ):void
		{
			borderTopAlpha = value[ 0 ];
			borderRightAlpha = value[ 1 ];
			borderBottomAlpha = value[ 2 ];
			borderLeftAlpha = value[ 3 ];
		}
		
		/**
		 * @param value
		 * @return 
		 */		
		public function set borderThickness( value:Array ):void
		{
			borderTopThickness = value[ 0 ];
			borderRightThickness = value[ 1 ];
			borderBottomThickness = value[ 2 ];
			borderLeftThickness = value[ 3 ];
		}
		
		
		//-----------------------------------------------------------------------------------
		// protected functions
		//-----------------------------------------------------------------------------------

		
		/**
		 * bg 그리는 메서드.
		 */		
		protected function drawBg():void
		{
			
			var g : Graphics = bg.graphics;
			g.clear();
			
			g.beginFill( backgroundColor, backgroundAlpha );
			
			g.drawRect( paddingLeft, paddingTop, 
				Math.max( viewWidth - paddingLeft - paddingRight, 0 ), 
				Math.max( viewHeight - paddingTop - paddingBottom, 0 ) );
			g.endFill();
			
			// 상단 보더
			if( borderTopThickness != 0 )
			{
				g.lineStyle( borderTopThickness, borderTopColor, borderTopAlpha );
				g.moveTo( 0, 0 );
				g.lineTo( viewWidth, 0 );
			}
			
			// 우측 보더
			if( borderRightThickness != 0 )
			{
				g.lineStyle( borderRightThickness, borderRightColor, borderRightAlpha );
				g.moveTo( viewWidth-1, 0 );
				g.lineTo( viewWidth-1, viewHeight-1 );
			}
			
			// 하단 보더
			if( borderBottomThickness != 0 )
			{
				g.lineStyle( borderBottomThickness, borderBottomColor, borderBottomAlpha );
				g.moveTo( viewWidth, viewHeight-1 );
				g.lineTo( 0, viewHeight-1 );
			}
			
			// 좌측 보더
			if( borderLeftThickness != 0 )
			{
				g.lineStyle( borderLeftThickness, borderLeftColor, borderLeftAlpha );
				g.moveTo( 0, viewHeight-1 );
				g.lineTo( 0, 0 );
			}
		}
		
		//-----------------------------------------------------------------------------------
		// internal functions
		//-----------------------------------------------------------------------------------
		
		
		
		
		//-----------------------------------------------------------------------------------
		// private functions
		//-----------------------------------------------------------------------------------
		
		
		
		//-----------------------------------------------------------------------------------
		// event handler
		//-----------------------------------------------------------------------------------
		
		/**
		 * @param e
		 */		
		protected function onAddedToStage(e:Event):void
		{
			add();
		}		
		
		/**
		 * @param e
		 */		
		protected function onRemoveFromStage(e:Event):void
		{
			remove();
		}
		
	}
}